package TextZone;

import java.awt.Color;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;

import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;

import Nuplet.Pair;



public class ColoredTextZone extends TextZone {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7937420545935859929L;
	private Hashtable<String,String> colormapbase;
	private Hashtable<Integer, String> colormap;
	private Collection<String> styles;
	private int deb_last;
	private int fin_last;
	private final Color sunken=new Color(210,210,210);
	//private final Color floating=Color.white;
	private Analyseur analyse;
	public ColoredTextZone(String name) {
		super(name);
		styles=new ArrayList<String>();
		setFontnSize("SansSerif",14);
		analyse=new Analyseur();
		deb_last=0;fin_last=0;
		this.setBackground(sunken);

	}
	public void setIgnoreChar(Character ignore){
		analyse.setIgnoreChar(ignore);
	}
	public void setColorMap( Hashtable<String,String> cm) {
		analyse.setColormap(cm);colormapbase=new Hashtable<String,String>(cm);
		styles.addAll(cm.values());
		addStylesToDocument(this.getStyledDocument());
	}
	public void setSeparator(Collection<Character> sep){
		analyse.setSeparator(sep);

	}
	public void setEnvironment_Delimiters(Hashtable<String,Pair<String, Pair<String, Boolean>>> delim) {
		analyse.setEnvDelim(delim);
		for (Iterator<Pair<String, Pair<String, Boolean>>> e=delim.values().iterator();e.hasNext();){
			String style=e.next().getRight().getLeft();
			addStyleToDocument(this.getStyledDocument(),style);
		}
	}

	public void setText(String t){
		//int p=this.getCaretPosition();
		super.setText(t);
		//this.setCaretPosition(p);
		if (getsaved()){
			colorize();
		}
	}
	/**
	 * @param (mot,couleur)
	 */
	public void addToColorMap(String a, String b) {
		analyse.addToColorMap(a, b);
		styles.add(b);
		addStyleToDocument(this.getStyledDocument(),b);
	}
	public void ColorMapReset() {
		analyse.setColormap(colormapbase);
	}
	public void colorize(){
		long timer=Calendar.getInstance().getTimeInMillis();
		String text=this.getText();
		int deb=0;int fin=text.length();
		StyledDocument doc = this.getStyledDocument();
		Style tmp=doc.getStyle(Analyseur.REGULAR);
		StyleConstants.setBackground(tmp, sunken);
		int t_pos=deb_last;
		int newpos;
		colormap=analyse.parse(text,deb,fin,this.getCaretPosition());
		ArrayList<Integer> keys;
		keys=ordre(colormap);
		doc.setCharacterAttributes(deb_last, fin_last-deb_last,tmp, true);
		if (keys!=null){
			for (int i=0;i < keys.size();i++ ){
				newpos=keys.get(i);	
				doc.setCharacterAttributes(t_pos, newpos-t_pos,tmp, true);
				tmp=doc.getStyle(colormap.get(newpos));
				StyleConstants.setBackground(tmp, sunken);
				t_pos=newpos;
			}
		}
		System.out.print((Calendar.getInstance().getTimeInMillis()-timer) + "ms, ");
	}

	public void setFontnSize(String Font,int size){
		StyledDocument doc = this.getStyledDocument();
		Style def = StyleContext.getDefaultStyleContext().
		getStyle(StyleContext.DEFAULT_STYLE);

		doc.addStyle("regular", def);
		StyleConstants.setFontFamily(def, Font);
		StyleConstants.setFontSize(def,size);

		addStylesToDocument(doc);
		doc.setLogicalStyle(0, getStyle("regular"));
	}
	public void setFontSize(int size){
		StyledDocument doc = this.getStyledDocument();
		Style def = StyleContext.getDefaultStyleContext().
		getStyle(StyleContext.DEFAULT_STYLE);

		doc.addStyle("regular", def);
		StyleConstants.setFontSize(def,size);
		addStylesToDocument(doc);

	}
	public void setFontSizeZoom() {
		StyledDocument doc = this.getStyledDocument();
		Style def = StyleContext.getDefaultStyleContext().
		getStyle(StyleContext.DEFAULT_STYLE);

		doc.addStyle("regular", def);

		StyleConstants.setFontSize(def,StyleConstants.getFontSize(def)+1);
		addStylesToDocument(doc);
	}
	public void setFontSizeUnZoom() {
		StyledDocument doc = this.getStyledDocument();
		Style def = StyleContext.getDefaultStyleContext().
		getStyle(StyleContext.DEFAULT_STYLE);

		doc.addStyle("regular", def);

		StyleConstants.setFontSize(def,StyleConstants.getFontSize(def)-1);
		addStylesToDocument(doc);
	}
	protected void addStylesToDocument(StyledDocument doc) {
		if (!styles.isEmpty())
			for (Iterator<String> e= styles.iterator();e.hasNext();){
				addStyleToDocument(doc,e.next());
			}
	}
	protected void addStyleToDocument(StyledDocument doc,String style) {
		//Initialize some styles.
		Style regular = doc.getStyle("regular");
		Style s = doc.addStyle(style, regular);
		int size=StyleConstants.getFontSize(regular);
		int rel=0;
		String rest=style;
		boolean pass=true;
		while(pass){ 
			if (rest.startsWith("italic")) StyleConstants.setItalic(s, true);
			else if (rest.startsWith("underline")) {rest=rest.substring(9);StyleConstants.setUnderline(s, true);}
			else if (rest.startsWith("strikethrough")) {rest=rest.substring(13);StyleConstants.setStrikeThrough(s, true);}
			else if (rest.startsWith("small")){ rest=rest.substring(5);size-=2 ;StyleConstants.setFontSize(s,size-rel);}
			else if (rest.startsWith("bold")){rest=rest.substring(4); StyleConstants.setBold(s, true);}
			else if (rest.startsWith("large")){rest=rest.substring(5); size+=2 ;StyleConstants.setFontSize(s,size+rel);}
			else if (rest.startsWith("very")) {rest=rest.substring(4);if (size>4) rel*=2;}
			else pass=false;
		}

		StyleConstants.setForeground(s,getColor(rest));	
	}
	protected Color getColor(String color){
		if (color.equals("red"))return Color.red;
		if (color.equals("green"))return Color.green;
		if (color.equals("gray"))return Color.gray;
		if (color.equals("blue"))return Color.blue;
		if (color.equals("white"))return Color.white;
		if (color.equals("black"))return Color.black;
		if (color.equals("magenta"))return Color.magenta;
		if (color.equals("orange"))return Color.orange;
		if (color.equals("cyan"))return Color.cyan;
		if (color.equals("darkgray"))return Color.darkGray;
		if (color.equals("pink"))return Color.pink;
		if (color.equals("lightgray"))return Color.lightGray;
		if (color.equals("yellow"))return Color.yellow;
		return this.getForeground();
	}

	public void color_zone(int deb, int fin,Color floating) {
		StyledDocument doc = this.getStyledDocument();
		int curseur_pos=this.getCaretPosition();
		Style tmp=doc.getStyle(Analyseur.REGULAR);
		StyleConstants.setBackground(tmp, sunken);
		int t_pos=deb_last;
		int newpos;
		String text=this.getText();
		ArrayList<Integer> keys;
		colormap=analyse.parse(text,deb_last,fin_last);
		keys=ordre(colormap);
		doc.setCharacterAttributes(deb_last, fin_last-deb_last,tmp, true);
		if (keys!=null){
			for (int i=0;i < keys.size();i++ ){
				newpos=keys.get(i);	
				doc.setCharacterAttributes(t_pos, newpos-t_pos,tmp, true);
				tmp=doc.getStyle(colormap.get(newpos));
				StyleConstants.setBackground(tmp, sunken);
				t_pos=newpos;
			}
		}
		colormap=analyse.parse(text,deb,fin,curseur_pos);
		keys=ordre(colormap);
		StyleConstants.setBackground(tmp, floating);
		if (keys!=null){
			deb_last=keys.get(0);
			if (deb_last>deb) deb_last=deb;
			fin_last=keys.get( keys.size()-1);
			if (fin_last<fin) fin_last=fin;
			t_pos=0;
			t_pos=deb_last;
			for (int i=0;i < keys.size();i++ ){
				newpos=keys.get(i);
				doc.setCharacterAttributes(t_pos, newpos-t_pos, tmp, true);
				tmp=doc.getStyle(colormap.get(newpos));
				StyleConstants.setBackground(tmp, floating);
				t_pos=newpos;
			}
		}
		tmp=doc.getStyle(Analyseur.REGULAR);


	}
	private ArrayList<Integer> ordre(Hashtable<Integer, String> colormap2) {
		if (colormap2.isEmpty()) return null;
		ArrayList<Integer> ret=new ArrayList<Integer>();
		int i=0;
		int key;
		Enumeration<Integer> e=colormap2.keys();
		ret.add(0,e.nextElement());
		i++;
		while(e.hasMoreElements()){
			key=e.nextElement();
			while (i<ret.size() && key > ret.get(i)){
				i++;
			}
			while (i> 0 && key < ret.get(i-1)){
				i--;
			}
			ret.add(i,key);

		}

		return ret;
	}

}
